package deviceinfo.wsm.com.deviceinfo.cpu;

import android.os.Build;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.LinkedHashMap;
import java.util.Scanner;

import deviceinfo.wsm.com.deviceinfo.common.FormatUtils;

/**
 * Created by 王家宝 on 2018/7/5.
 * TEL:18241150668
 * MAIL:639586819@qq.com
 */

public class CPUInfoUtils {

    private static String CPU_PRE = "/sys/devices/system/cpu/cpu";
    private static String CPU_CURRENT = "/cpufreq/scaling_cur_freq";
    private static String CPU_MIN = "/cpufreq/cpuinfo_min_freq";
    private static String CPU_MAX = "/cpufreq/cpuinfo_max_freq";

    public static LinkedHashMap<String, String> getAll() {
        LinkedHashMap<String, String> allData = new LinkedHashMap<>();
        int cpuNums = getNumberOfCPUCores();
        allData.put("cpu核心数", cpuNums + "");
        if (cpuNums > 0) {
            for (int i = 0; i < cpuNums; i++) {
                try {
                    allData.put("cpu" + i + "当前频率", FormatUtils.formatCpuRate(getCPUFrequencyCurrent(CPU_PRE + i + CPU_CURRENT)));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    allData.put("cpu" + i + "最大频率", FormatUtils.formatCpuRate(getCPUFrequencyCurrent(CPU_PRE + i + CPU_MAX)));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    allData.put("cpu" + i + "最小频率", FormatUtils.formatCpuRate(getCPUFrequencyCurrent(CPU_PRE + i + CPU_MIN)));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            allData.put("cpu名称", Build.SUPPORTED_ABIS[0]);
            allData.put("cpu序列号", getCPUSerial());
            return allData;
        } else {
            return allData;
        }

    }

    static String[] mArmArchitecture = new String[5];

    public static String[] getCpuArchitecture() {

        try {
            InputStream is = new FileInputStream("/proc/cpuinfo");
            InputStreamReader ir = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(ir);
            try {
                String nameProcessor = "Processor";
                String nameFeatures = "Features";
                String nameModel = "model name";
                String nameCpuFamily = "cpu family";
                while (true) {
                    String line = br.readLine();
                    String[] pair = null;
                    if (line == null) {
                        break;
                    }
                    pair = line.split(":");
                    if (pair.length != 2)
                        continue;
                    String key = pair[0].trim();
                    String val = pair[1].trim();
                    if (key.compareTo(nameProcessor) == 0) {
                        String n = "";
                        if (val.indexOf("AArch64") >= 0) {
                            mArmArchitecture[0] = "aarch64";
                            mArmArchitecture[1] = 64 + "";
                            continue;
                        } else {

                            for (int i = val.indexOf("ARMv") + 4; i < val.length(); i++) {
                                String temp = val.charAt(i) + "";
                                if (temp.matches("\\d")) {
                                    n += temp;
                                } else {
                                    break;
                                }
                            }
                        }
                        mArmArchitecture[0] = "ARM";
                        mArmArchitecture[1] = Integer.parseInt(n) + "";
                        continue;
                    }

                    if (key.compareToIgnoreCase(nameFeatures) == 0) {
                        if (val.contains("neon")) {
                            mArmArchitecture[2] = "neon";
                        }
                        continue;
                    }

                    if (key.compareToIgnoreCase(nameModel) == 0) {
                        if (val.contains("Intel")) {
                            mArmArchitecture[0] = "INTEL";
                            mArmArchitecture[2] = "atom";
                        }
                        continue;
                    }

                    if (key.compareToIgnoreCase(nameCpuFamily) == 0) {
                        mArmArchitecture[1] = Integer.parseInt(val) + "";
                        continue;
                    }
                }
            } finally {
                br.close();
                ir.close();
                is.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return mArmArchitecture;
    }

    private static final FileFilter CPU_FILTER = new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            String path = pathname.getName();
            //regex is slow, so checking char by char.
            if (path.startsWith("cpu")) {
                for (int i = 3; i < path.length(); i++) {
                    if (path.charAt(i) < '0' || path.charAt(i) > '9') {
                        return false;
                    }
                }
                return true;
            }
            return false;
        }
    };

    private static int getNumberOfCPUCores() {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
            // Gingerbread doesn't support giving a single application access to both cores, but a
            // handful of devices (Atrix 4G and Droid X2 for example) were released with a dual-core
            // chipset and Gingerbread; that can let an app in the background run without impacting
            // the foreground application. But for our purposes, it makes them single core.
            return 1;
        }
        int cores;
        try {
            cores = new File("/sys/devices/system/cpu/").listFiles(CPU_FILTER).length;
        } catch (SecurityException e) {
            cores = 0;
        } catch (NullPointerException e) {
            cores = 0;
        }
        return cores;
    }

    public static int getCPUFrequencyMin(String cpuMin) throws Exception {
        return CPUInfoUtils.readSystemFileAsInt(cpuMin);
    }

    public static int getCPUFrequencyMax(String cpuMax) throws Exception {
        return CPUInfoUtils.readSystemFileAsInt(cpuMax);
    }

    private static int getCPUFrequencyCurrent(String cpuCurrent) throws Exception {
        return CPUInfoUtils.readSystemFileAsInt(cpuCurrent);
    }

    private static int readSystemFileAsInt(final String pSystemFile) throws Exception {
        InputStream in = null;
        try {
            final Process process = new ProcessBuilder(new String[]{
                    "/system/bin/cat", pSystemFile}).start();

            in = process.getInputStream();
            final String content = readFully(in);
            return Integer.parseInt(content);
        } catch (final Exception e) {
            throw new Exception(e);
        }
    }

    private static final String readFully(final InputStream pInputStream) throws IOException {
        final StringBuilder sb = new StringBuilder();
        final Scanner sc = new Scanner(pInputStream);
        while (sc.hasNextLine()) {
            sb.append(sc.nextLine());
        }
        return sb.toString();
    }


    private static String getCpuName() {
        try {
            FileReader fr = new FileReader("/proc/cpuinfo");
            BufferedReader br = new BufferedReader(fr);
            String text = br.readLine();
            String[] array = text.split(":\\s+", 2);
            for (int i = 0; i < array.length; i++) {
            }
            return array[1];
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取cpu序列号
     *
     * @return
     */
    private static String getCPUSerial() {
        String str = "", strCPU = "", cpuAddress = "0000000000000000";
        try {
            //读取CPU信息
            Process pp = Runtime.getRuntime().exec("cat /proc/cpuinfo");
            InputStreamReader ir = new InputStreamReader(pp.getInputStream());
            LineNumberReader input = new LineNumberReader(ir);
            //查找CPU序列号
            for (int i = 1; i < 100; i++) {
                str = input.readLine();
                if (str != null) {
                    //查找到序列号所在行
                    if (str.indexOf("Serial") > -1) {
                        //提取序列号
                        strCPU = str.substring(str.indexOf(":") + 1,
                                str.length());
                        //去空格
                        cpuAddress = strCPU.trim();
                        break;
                    }
                } else {
                    //文件结尾
                    break;
                }
            }
        } catch (IOException ex) {
            //赋予默认值
            ex.printStackTrace();
        }
        return cpuAddress;
    }


}
